package route

import (
	"encoding/json"
	"github.com/gorilla/mux"
	"net/http"
	mysqlMod "route/mysql"
	"sync"
	"time"
)

type routeClass int

// 路由类型
const (
	NormalRoute routeClass = 1 + iota // 正常路由(后台)
	PreRoute
)

// Rule 路由规则
type Rule struct {
	// 公共参数
	ShortRoute  string                                       // 短路由, 用于组册路由
	Description string                                       // 简单描述
	Handler     func(w http.ResponseWriter, r *http.Request) // Handle 函数
	RouteClass  routeClass                                   // 路由分类(Normal)

	// 可选参数
	Method []string

	Exact    bool // 是否最后的路由(精确路由)
	SubRoute Map  // 子路由, [是选择这种不带 hash 的数组, 还是应该和 routeMap 一样选择 hash-map ?]
}

func (r *Rule) Rule2JSON() JSONRule {
	return JSONRule{
		ShortRoute: r.ShortRoute,
		RouteClass: r.RouteClass,
		Method:     r.Method,
		TimeCreate: time.Now(),
	}
}

type JSONRule struct {
	ShortRoute string     `json:"short_route"`
	RouteClass routeClass `json:"route_class"` // 路由分类

	// 可选参数
	Method     []string  `json:"method"`
	TimeCreate time.Time `json:"time_create"`
}

type Map struct {
	sync.RWMutex
	m map[string]*Rule
}

// RouteRange routeMap 通过 长路由 和 routeRule 来构建路由表
func (r *Rule) RouteRange(longRoute string) *mux.Router {
	router := mux.NewRouter()
	if !r.Exact {
		r.SubRoute.Lock()
		for longRoute, vs := range r.SubRoute.m {
			router.Path(vs.ShortRoute).Handler(vs.RouteRange(longRoute))
		}
		r.SubRoute.Unlock()
	} else {
		route := router.HandleFunc(r.ShortRoute, r.Handler)
		if len(r.Method) != 0 {
			route.Methods(r.Method...)
		}
		// ... 其他参数
	}
	return router
}

func init() {
	routeMap.Lock()
	defer routeMap.Unlock()
	// 全路由, 用于与 route.GetPathTemplate() 配对
	routeMap.m["/api/v1/backstage/exam"] = &Rule{
		ShortRoute:  "/exam",
		Description: "测试用路由",
		Handler:     testRoute,
		RouteClass:  NormalRoute,
		Method:      []string{"POST"},
		Exact:       true,
	}

	routeMap.m["/api/v1/backstage/pre-file"] = &Rule{
		ShortRoute:  "/pre-file",
		Description: "文件上传前获取唯一标志符",
		Handler:     PreFileUpload,
		RouteClass:  PreRoute,
		Method:      []string{"GET"},
		Exact:       true,
	}
	routeMap.m["/api/v1/backstage/file"] = &Rule{
		ShortRoute:  "/file",
		Description: "文件处理",
		RouteClass:  NormalRoute,
		SubRoute: Map{
			m: map[string]*Rule{
				"/api/v1/backstage/file/{file} POST": &Rule{
					ShortRoute:  "/{file}",
					Handler:     FileUpload,
					Description: "文件上传",
					RouteClass:  NormalRoute,
					Method:      []string{"POST"},
					Exact:       true,
				},
				"/api/v1/backstage/file/{file} GET": &Rule{
					ShortRoute:  "/{file}",
					Handler:     FileDownload,
					Description: "文件下载",
					RouteClass:  NormalRoute,
					Method:      []string{"GET"},
					Exact:       true,
				},
				"/api/v1/backstage/file GET": &Rule{
					ShortRoute:  "/",
					Description: "列出所有文件",
					Handler:     FileList,
					RouteClass:  NormalRoute,
					Method:      []string{"GET"},
					Exact:       true,
				},
			},
		},
	}
}

type record struct {
	requestURI string
	id         int
}

// MdlRecordOperation 记录下当前的操作信息
// id, requestURI := idR, r.RequestURI
func MdlRecordOperation(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		desc, detail := "", `{"short_route":"","route_class":1,"method":[]}`
		// v, ok := routeMap.Load(requestURI)
		record, ok := r.Context().Value(RecCtx).(record)
		if !ok {
			http.Error(w, "record failed", http.StatusInternalServerError)
			return
		}

		go func() {
			value, ok := routeMap.m[record.requestURI]

			if ok {
				// PreRoute 不记录
				if value.RouteClass == PreRoute {
					return
				}

				desc = value.Description
				jsonvalue := value.Rule2JSON()
				if tmp, err := json.Marshal(jsonvalue); err == nil {
					detail = string(tmp)
				}
			}

			// 记录
			_, err := mysqlMod.Exec("INSERT INTO admin_log (description, id_admin_user, detail_involve) VALUES (?, ?, ?)", desc, record.id, detail)
			if err != nil {
				return
			}

			// 查询当前用户条数
			var count int
			rows, err := mysqlMod.Query("SELECT COUNT(id_admin_user=? OR NULL) FROM admin_log", record.id)
			if err != nil {
				return
			}

			if !rows.Next() {
				// 没有记录 ? 总之没有计算成功
				return
			}

			rows.Scan(&count)
			if count > MaxLog {
				// 超出限制, 删除部分历史记录
				// NOTE: 可能不需要 ?
				// NOTE: !注意! 删除的数量和限制是不同的, 理由见 MaxLog 的定义
				mysqlMod.Exec("DELECT FROM admin_log ORDER BY id DESC LIMIT ?", count-DisplayLog)
			}
		}()

		next.ServeHTTP(w, r)
	})
}
